require "task_list/query"

# 新規登録用タスクを生成するためのファクトリ
# 
class TaskFactory
  # 文字列で指定された新規登録用タスクを解釈し、タスクを構築する。
  # @param user_id Integer タスク生成ユーザの識別子。非null。
  # @param string String タスクの文字列表記。非null。
  # @return Task 文字列を解釈した結果得られたタスクオブジェクト。非nil。
  # TODO エラーチェックを行っていない。
  # TODO タスクのステータスが、DB上では「done」の2値
  # (p|priority:=?priority)? title (s|status:=?done:undone)? (d|due:=?2009-12-14T00:00:00)?
  public
  def self.create(user_id, string)
    # 検索クエリ文字列の解釈・分解
    priority, status, due, title = parse(string)
    return create_task(user_id, priority, status, due, title)
  end
  
  # 識別子を指定された更新対象タスクを、文字列で指定された更新情報を解釈して、更新用タスクオブジェクトを生成する。
  # ただし、個別にパラメタ指定されていた場合は、そちらの情報を優先する。
  # @param task_id Integer 更新対象タスクの識別子。非nil。見つからなければ新規作成用オブジェクトを返す。
  # @param user_id Integer タスクを入力したユーザの識別子。非nil
  # @param priority Integer タスクの優先度。nilならばstringから取得。
  # @param status String タスクの状態。done, undoneのいずれか。nilならばstringから取得。
  # @param due Date タスクの期日。nilならばstringから取得。
  # @param title タスクの表題。nilならばstringから取得。
  # @param string String タスクの文字列表記。非null。個別指定がnilで、こちらにも情報がないパラメタは更新しない。
  # @return Task 文字列を解釈した結果得られたタスクオブジェクト。非nil。
  # (p|priority:=?priority)? title (s|status:=?done:undone)? (d|due:=?2009-12-14T00:00:00)?
  public
  def self.modify(task_id, user_id, priority, status, due, title, string)
    parsed_priority, parsed_status, parsed_due, parsed_title = parse(string)
    priority = parsed_priority if (priority == nil)
    status = parsed_status if (status == nil)
    due = parsed_due if (due == nil)
    title = parsed_title if (title == nil)
    return modify_task(task_id, user_id, priority, status, due, title)
  end
  
  # 与えられたタスク文字列を解釈し、記述された新規登録タスク情報を取得する。
  # 記述内に存在しなかったタスク情報は、指定されなかったものと解釈する。
  # @param string String タスク文字列。nilならば、すべての返値がnil。
  # @return priority Integer タスクの優先度。未設定ならnil。
  # @return status String タスクの実行ステータス。'done' または 'undone'。未設定ならnil。
  # @return due Date タスクの実行期限。制限なしならばnil。
  # @return title String タスクの表題。未設定ならnil。
  private
  def self.parse(string)
    if(string == nil)
      return nil, nil, nil, nil
    end

    title = ""
    priority = nil
    status = nil
    due = nil
    
    terms = string.split(/\s+/)
    terms.each{|term| begin
     (key, value) = term.split(/:/, 2)
        if value == nil then
          title += " " + key
        elsif key =~ /^p|priority$/
          priority_string = remove_operator(value)
          priority = priority_string.to_i()
        elsif key =~ /^s|status$/
          status = remove_operator(value)
        elsif key =~ /^d|due$/
          due_value = remove_operator(value)
          due = DateTime.parse(due_value)
        else
          title += " " + key
        end
      end
    }
    title = (title == "") ? nil : title.strip!()
    return priority, status, due, title
  end
  
  # 引数に指定された各種設定値に基づき、タスクオブジェクトを生成する。
  # nil指定された引数は、設定値が未指定として、デフォルト値を与える。
  # @param user_id Integer タスクを入力したユーザの識別子。非nil
  # @param priority Integer タスクの優先度。nilならば1。
  # @param status String タスクの状態。done, undoneのいずれか。nilならばundone。
  # @param due Date タスクの期日。nilならば制限なし。
  # @param title タスクの表題。非nil。
  # @return Task 指定された設定値を持つタスクオブジェクト。非nil。
  public
  def self.create_task(user_id, priority, status, due, title)
    task = Task.new()
    task.user_id = user_id
    task.priority = (priority == nil) ? 1 : priority
    task.done = (status == 'done') ? true : false
    task.title = (title == nil) ? "" : title
    task.due = due
    return task
  end
  
  
  # 更新対象として指定されたタスクの情報を永続データ領域から取得し、
  # 引数に指定された各種設定値に基づいて更新用タスクオブジェクトを生成する。
  # nil指定された引数は、未更新として、値を変更しない。
  # @param task_id Integer 更新対象タスクの識別子。非nil。見つからなければ新規作成用オブジェクトを返す。
  # @param user_id Integer タスクを入力したユーザの識別子。非nil
  # @param priority Integer タスクの優先度。nilならば更新しない。
  # @param status String タスクの状態。done, undoneのいずれか。nilならば更新しない。
  # @param due Date タスクの期日。nilならば更新しない。
  # @param title タスクの表題。nilならば更新しない。
  # @return Task 更新用の設定を行ったタスクオブジェクト。非nil。
  private
  def self.modify_task(task_id, user_id, priority, status, due, title)
    task = Task.find(task_id)
    if (task == nil)
      return create_task(user_id, priority, status, due, title)
    end
    task.priority = priority if (priority != nil)
    if (status != nil)
      task.done = (status == 'done') ? true : false
    end
    task.title = title if (title != nil)
    task.due = due if (title != nil)
    return task
  end
  
  # 与えられた文字列が、等号演算子とオペランドからなっていた場合に、等号演算子を削除して返す。
  # @param 等号演算子とオペランドをつなげた文字列。"=operand"。nilならば、nilを返す。等号演算子がなければ、引数をそのままかえす。
  # @return value オペランド。
  private
  def self.remove_operator(string)
    if string =~ /^(=)/ then
      string.slice!(0,1)
    end
    return string
  end
end
